package com.ra.landlord;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.jdbc.ReturningWork;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.util.bean.ModelUtil;
import com.ra.landlord.constant.FeeRuleType;
import com.ra.system.Version;

@Service
public class MeterService {

	private static final Log logger = LogFactory.getLog(MeterService.class);
	
	@Resource
	private GenericService genericService;
	
	@Resource
	private LandlordUserService landlordUserService;
	
	@Resource
	private RoomService roomService;
	
	@Resource
	private FeeAdditionService feeAdditionService;
	
	@Resource
	private FeeRecordService feeRecordService;
	
	@Resource
	private FeeService feeService;
	
	@PersistenceContext(unitName = "espirit")
	private EntityManager em;

	// 0表示未抄表
	private Meter UNREAD_METER;
	// 1表示手动修改了值
	private Meter MODIFIED_METER;
	// 2表示固定收费
	private Meter FIXED_METER;
	
	public Meter getUnReadMeter() {
		if (UNREAD_METER == null) {
			UNREAD_METER = checkAndLoadMeter(0);
		}
		return UNREAD_METER;
	}
	
	public Meter getModifedMeter() {
		if (MODIFIED_METER == null) {
			MODIFIED_METER = checkAndLoadMeter(1);
		}
		return MODIFIED_METER;
	}
	
	public Meter getFixedMeter() {
		if (FIXED_METER == null) {
			FIXED_METER = checkAndLoadMeter(2);
		}
		return FIXED_METER;
	}

	private Meter checkAndLoadMeter(final Integer id) {
		Meter meter = genericService.load(Meter.class, id);
		if (meter == null) {
			meter = new Meter();
			meter.setId(id);
			meter.setCount(new BigDecimal(0));
			meter.setCheckTime(Calendar.getInstance().getTime());
			
			LandlordOwnerVIPUser landlordUser = landlordUserService.loadOrCreateLandlordUserForAdmin();
			meter.setLandlordUser(landlordUser);
			meter.setReader(landlordUser);
			meter.setPrice(new BigDecimal(0));
			meter.setStatus(1);
			meter.setVersion(1);
			
			final Meter model = meter;
			genericService.doReturningWork(new ReturningWork<Boolean>() {

				@Override
				public Boolean execute(Connection connection) throws SQLException {
					// no RelationId
					String sql = "insert into ra_meter (MeterId, check_time, MeterCount, createuserid, price, admin_id,"
							+ " data_status, version_id) values (?, ?, ?, ?, ?, ?, ?, ?)";
					PreparedStatement ps = connection.prepareStatement(sql);
					int index = 0;
					if (model.getId() == 0) {
						// 直接插入id为0的数据不成功， 故先用1插入，然后修改为0
						ps.setInt(++index, 1);									// MeterId
					} else {
						ps.setInt(++index, model.getId());						// MeterId
					}
					ps.setDate(++index, new java.sql.Date(model.getCheckTime().getTime()));		// check_time
					ps.setBigDecimal(++index, model.getCount());			// MeterCount
					ps.setInt(++index, model.getLandlordUser().getId());	// createuserid
					ps.setBigDecimal(++index, model.getPrice());			// price
					ps.setInt(++index, model.getReader().getId());			// admin_id
					ps.setInt(++index, model.getStatus());					// data_status
					ps.setInt(++index, model.getVersion());					// version_id
					int ret = ps.executeUpdate();
					
					if (model.getId() == 0) {
						sql = "UPDATE ra_meter SET MeterId=0 WHERE MeterId=1";
						ps.executeUpdate(sql);
					}
					
					ps.close();
					
					return ret > 0;
				}
			});
		}
		return meter;
	}
	
	@Rest(type="search")
	public List<FeeRuleCfgDesc> searchMeterCategory() {
		FeeRuleCfgDesc feeRuleCfgDesc = new FeeRuleCfgDesc();
		feeRuleCfgDesc.setType(FeeRuleType.meter);
		feeRuleCfgDesc.setStatus(Version.STATUS_VALID);
		
		String strShort = "isShare"; 
		String strOrderBy = "ASC";
		PageInfo<FeeRuleCfgDesc> pageInfo = this.genericService.search(feeRuleCfgDesc, 0, 100, strShort, strOrderBy, false, null, null, true, false);
		
		return pageInfo.getData();
	}
	
	@Transactional
    @Rest(type="add")
    public Meter add(Meter model) {
		BigDecimal price = genericService.load(model.getFeeRule()).getFeeRuleCfg().getFeeRuleCfgCalc().getPrice();
		model.setPrice(price);
		model.setReader(landlordUserService.getLoginUser());
		model.setCheckTime(Calendar.getInstance().getTime());
		
		FeeRule feeRule = genericService.load(model.getFeeRule());
		LandlordUser landlordUser = feeRule.getRoom().getLandlordUser();
		model.setLandlordUser(landlordUser.getOwnerUser());
		
		return genericService.add(model);
	}
	
	/**
	 * 添加抄表记录
	 * @param models
	 * @return
	 */
	@Transactional
    @Rest(type="add")
    public Boolean addMeters(List<Meter> models) {
		
		return addMetersNew(models);
		
		/*List<Meter> meters = new ArrayList<Meter>();
		//Map<Integer, Room> rooms = new HashMap<>();
		for (Meter model : models) {
			//System.out.println("==提交的model="+model.getCount()+" ,rule="+model.getFeeRule().getId()+",  time="+model.getCheckTime());
			FeeRule feeRule = genericService.load(model.getFeeRule());
			if (feeRule == null) {
				continue;
			}
			List<Meter> dbMeters = feeRule.getMeters();
			Date dbMaxTime = null;
			if (dbMeters != null && dbMeters.size() > 0) {
				dbMaxTime = dbMeters.get(0).getCheckTime();
			}

			BigDecimal price = feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice();
			model.setPrice(price.setScale(2,BigDecimal.ROUND_HALF_UP));
			model.setReader(landlordUserService.getLoginUser());
			//抄表时间，取系统时间
			Date modelCheckTime = model.getCheckTime();
			Calendar calendar = Calendar.getInstance();
			if (modelCheckTime != null) {
				Calendar modelCalendar = Calendar.getInstance();
				modelCalendar.setTime(modelCheckTime);
				calendar.set(Calendar.YEAR, modelCalendar.get(Calendar.YEAR));
				calendar.set(Calendar.MONTH, modelCalendar.get(Calendar.MONTH));
				calendar.set(Calendar.DATE, modelCalendar.get(Calendar.DATE));
			}
			if (dbMaxTime != null) {
				if (dbMaxTime.after(calendar.getTime())) {
					calendar.setTime(new Date(dbMaxTime.getTime() + 1000));
				}
			}
			model.setCheckTime(calendar.getTime());
			LandlordUser landlordUser = landlordUserService.getLoginUser();
			model.setLandlordUser(landlordUser.getOwnerUser());
			Meter meter = genericService.add(model);
			meters.add(meter);
			
			//抄表后，将费用对应的房间的feerecord删除
			if (feeRule.getRoom() != null) {
				feeRecordService.deleteFeeRecordByRoom(feeRule.getRoom());
			} else if (feeRule.getShareUnit() != null) {
				for (RoomShareUnit roomShareUnit : feeRule.getShareUnit().getRoomShareUnits()) {
					feeRecordService.deleteFeeRecordByRoom(roomShareUnit.getRoom());
				}
			}
			
			// 统计涉及的room
			//rooms.put(feeRule.getRoom().getId(), feeRule.getRoom());
		}
		// 通知room重算费用
//		for (Room room : rooms.values()) {
//			roomService.updateSingleRoomFee(room, true);
//		}
		return meters;*/
	}
	
	@Transactional
    @Rest(type="update")
	public Meter update(Meter model) {
		BigDecimal price = genericService.load(model.getFeeRule()).getFeeRuleCfg().getFeeRuleCfgCalc().getPrice();
		model.setPrice(price);
		return genericService.update(model);
	}
	
	/**
	 * 根据房间的费用配置规则，查询对应的仪表刻度集合
	 * @param feeRuleId
	 * @return
	 */
	@Rest(type="search")
	public List<Meter> searchMeterByFeeRule(Integer feeRuleId) {
		List<Meter> meters = new ArrayList<>();
		FeeRule feeRule = new FeeRule();
		feeRule.setId(feeRuleId);
		feeRule = genericService.load(feeRule);
		if(feeRule != null){
			meters = feeRule.getMeters();
		}
		//显示前10条抄表记录
		if(meters.size() >= 10){
			meters = meters.subList(0, 10);
		}
		for (Meter meter : meters) {
			if (isBeRelated(meter.getId())) {
				meter.setDeletable(false);
			}else{
				meter.setDeletable(true);
			}
		}
		
		return meters;
	}
	
	@Rest(type="search")
	public List<Room> searchMeterByRoom(Room model) {
		List<Room> rooms = new ArrayList<Room>();
		
		Room dbRoom = genericService.load(model);
		int today = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
		
		for (FeeRule matchedFeeRule : dbRoom.getFeeRules()) {
			if (matchedFeeRule.getFeeRuleCfg().getFeeRuleCfgDesc().getType() != FeeRuleType.meter) {
				continue;
			}
			List<Meter> lstMeter = matchedFeeRule.getMeters();
			Room room = new Room();
			ModelUtil.copy(dbRoom, room);
			if (lstMeter == null || lstMeter.size() == 0) {
				//初始化表刻度
				Meter initMeter = new Meter();
				initMeter.setCount(BigDecimal.valueOf(0));
				initMeter.setFeeRule(matchedFeeRule);
				initMeter.setCheckTime(null);
				room.setLastMeter(initMeter);
				rooms.add(room);
			}else if(lstMeter.size() >= 1){
				room.setLastMeter(lstMeter.get(0));
				if (lstMeter.size() > 1) {
					room.setLastLastMeter(lstMeter.get(1));
				}
				rooms.add(room);
			}
		}
		return rooms;
	}
	
	/**
	 * 查看该meterId是否被FeeAddition关联了
	 * @param meterId
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private boolean isBeRelated(Integer meterId){
		boolean bResult = false;
		String ql = "select a from " + FeeAddition.class.getName() + " a where (a.meter1.id = ? or a.meter2.id = ?) and a.fee.status != 0";
		List<Object> lstParams = new ArrayList<>();
		lstParams.add(meterId);
		lstParams.add(meterId);
		PageInfo<FeeAddition> pageInfos = genericService.searchByQl(new QLInfo(ql, lstParams), false); 
		if (pageInfos.getData() != null && pageInfos.getData().size() > 0) {
			bResult = true;
		}
		
		return bResult;
	}
	
	/**
	 * 删除抄表，逻辑删除
	 * @param model
	 * @return
	 */
	@Rest(type="delete")
	public Boolean deleteMeter(Meter model) {
		
		return deleteMeterNew(model);
		
		/*//应该加个校验，判断是否能删除
		Meter meter = genericService.load(model);
		meter.setStatus(0);
		meter = genericService.merge(meter);
		
		//删除抄表记录后，将费用对应的房间的feerecord删除
		FeeRule feeRule = meter.getFeeRule();
		if (feeRule.getRoom() != null) {
			feeRecordService.deleteFeeRecordByRoom(feeRule.getRoom());
		} else if (feeRule.getShareUnit() != null) {
			for (RoomShareUnit roomShareUnit : feeRule.getShareUnit().getRoomShareUnits()) {
				feeRecordService.deleteFeeRecordByRoom(roomShareUnit.getRoom());
			}
		}
		
		return meter;*/
	}
	
	@Rest(type="add")
	@Transactional
	public boolean addMetersNew(List<Meter> models) {
		for (Meter meter : models) {
			FeeRule feeRule = genericService.load(meter.getFeeRule());
			if (feeRule == null) {
				continue;
			}
			Meter emptyMeter = feeRule.getMeter(0);
			if (emptyMeter == null) {
				emptyMeter = genericService.load(Meter.class, 0);
			}
			FeeAdditionRecord feeAdditionRecordExample = new FeeAdditionRecord();
			feeAdditionRecordExample.setMeter1(emptyMeter);
			feeAdditionRecordExample.setMeter2(emptyMeter);
			feeAdditionRecordExample.setFeeRuleCfg(feeRule.getFeeRuleCfg());
			FeeAdditionRecord needDeleteFeeAdditionRecord = genericService.searchByModel(feeAdditionRecordExample, Condition.DEFAULT).getData(0);
			if (needDeleteFeeAdditionRecord != null) {
				FeeRecord dbFeeRecord = needDeleteFeeAdditionRecord.getFeeRecord();
				dbFeeRecord.getFeeAdditionRecords().remove(needDeleteFeeAdditionRecord);
				em.merge(dbFeeRecord);
			}
			
			if (meter.getCheckTime() == null) {
				meter.setCheckTime(new Date());
			}
			
			List<Meter> dbMeters = feeRule.getMeters();
			Meter prevMeter = null;
			if (dbMeters != null && dbMeters.size() > 0) {
				prevMeter = dbMeters.get(0);
			}
			
			if (prevMeter != null) {
				Calendar now = Calendar.getInstance();
				Calendar nowCheckTime = Calendar.getInstance(); 
				nowCheckTime.setTime(meter.getCheckTime());
				nowCheckTime.set(Calendar.HOUR, now.get(Calendar.HOUR));
				nowCheckTime.set(Calendar.MINUTE, now.get(Calendar.MINUTE));
				nowCheckTime.set(Calendar.SECOND, now.get(Calendar.SECOND));
				if (nowCheckTime.getTime().compareTo(prevMeter.getCheckTime()) <= 0) {
					nowCheckTime.setTime(prevMeter.getCheckTime());
					nowCheckTime.add(Calendar.SECOND, 1);
				}
				meter.setCheckTime(nowCheckTime.getTime());
			}
			meter.setPrice(feeRule.getFeeRuleCfg().getFeeRuleCfgCalc().getPrice());
			meter.setReader(landlordUserService.getLoginUser());
			meter.setLandlordUser(landlordUserService.getLoginUser().getOwnerUser());

			genericService.add(meter);
			feeService.generateMeterFee(feeRule);
		}
		return true;
	}
	
	/**
	 * 删除抄表
	 * @param model
	 */
	@Transactional
	public boolean deleteMeterNew(Meter model) {
		Meter meter = genericService.load(model);
		FeeAddition example = new FeeAddition();
		example.setMeter1(meter);
		List<FeeAddition> dbFeeAdditions = genericService.searchByModel(example, Condition.DEFAULT).getData();
		if (dbFeeAdditions != null && dbFeeAdditions.size() >0 ) {
			for (FeeAddition dbFeeAddition : dbFeeAdditions) {
				if (dbFeeAddition.getFee().getStatus() == FeeRecord.FEE_STATUS_RENT_DONE) {
					throw new ApplicationException("该抄表产生的费用已经收取，无法删除！");
				}
			}
			
		}
		
		FeeAdditionRecord feeAdditionRecordExample = new FeeAdditionRecord();
		feeAdditionRecordExample.setMeter1(meter);
		List<FeeAdditionRecord> dbFeeRecordAdditions = genericService.searchByModel(feeAdditionRecordExample, Condition.DEFAULT).getData();
		try{
			for (FeeAdditionRecord dbFeeAdditionRecord : dbFeeRecordAdditions) {
				FeeRecord dbFeeRecord = dbFeeAdditionRecord.getFeeRecord();
				if (FeeRecord.FEE_STATUS_RENT_TODO == dbFeeRecord.getStatus()) {
					dbFeeRecord.setAmountRecv(dbFeeRecord.getAmountRecv().subtract(dbFeeAdditionRecord.getPriceRecv()).setScale(2, RoundingMode.HALF_UP));
					genericService.delete(dbFeeAdditionRecord);
					genericService.merge(dbFeeRecord);
				}
			}
		} catch(Exception e) {
			throw new ApplicationException("系统异常,无法删除.");
		}
		meter.setStatus(0);
		genericService.merge(meter);
		return true;
	}
	
	
	/**
	 * 批量批表
	 * @return
	 */
	public List<RoomView> allSearchFromBuild(Integer buildingId, Integer meterTypeId){
		
		if( meterTypeId == null ){
			List<FeeRuleCfgDesc> meterTypes = searchMeterCategory();
			if( meterTypes != null && meterTypes.size() > 0 ){
				meterTypeId = meterTypes.get(0).getId();
			}
		}
		List<RoomDBVO> rooms = roomService.searchWithMeter(buildingId,meterTypeId,0,0,null,null);
		List<RoomView> results = new ArrayList<RoomView>();
		
		for (RoomDBVO roomDBVO : rooms) {
			RoomView view = new RoomView();
			view.setName(roomDBVO.getName());
			roomDBVO.getId();
			view.setId(roomDBVO.getId());
			
			Meter beforeLastMeter = roomDBVO.getLastLastMeter();
			if(beforeLastMeter != null){
				view.setBeforeLastMeterId(beforeLastMeter.getId());
				view.setBeforeLastMeterCount(beforeLastMeter.getCount());
				view.setBeforeLastMeterTime(beforeLastMeter.getCheckTime());
			}
			Meter lastMeter = roomDBVO.getLastMeter();
			if(lastMeter != null){
				view.setLastMeterCount(lastMeter.getCount());
				view.setLastMeterId(lastMeter.getId());
				view.setLastMeterTime(lastMeter.getCheckTime());
				FeeRule rule = lastMeter.getFeeRule();
				if(null != rule){
					view.setFeeRuleId(rule.getId());
				}
			}
			Meter currMeter = roomDBVO.getCurrentMeter();
			if( currMeter != null){
				view.setCurrMeterCount(currMeter.getCount());
				view.setCurrMeterId(currMeter.getId());
				view.setCurrMeterTime(currMeter.getCheckTime());
			}
			results.add(view);
		}
		
		return results;
	}
	
	/**
	 * 修复集中式的仪表费用
	 * @param buildingId
	 * @return
	 */
	public boolean repairMeterFee(Integer buildingId, String testRoomName){
		Building dbBuilding = genericService.load(Building.class,buildingId);
		LandlordUser landlordUser = landlordUserService.getLoginUser();
		if (dbBuilding.getLandlordUser().getId().equals(landlordUser.getOwnerUser().getId()) || "admin".equals(landlordUser.getPhone()) ) {
			
			Room model = new Room();
			model.setHasPay(false);
			BuildingFloor buildingFloor = new BuildingFloor();
			buildingFloor.setId(0);
			model.setBuildingFloor(buildingFloor);
			model.setBuilding(dbBuilding);
			Integer chargState = null;
			if (model.getHasPay() != null) {
				chargState = model.getHasPay() ? 0 : 1;
			}
			
			List<Room> rooms = roomService.searchRoomsNew(model, null, chargState, null).getData();
			
			if (rooms != null && rooms.size() > 0) {
				for (Room room : rooms) {
					List<FeeRule> feerules = room.getFeeRules();
					if (feerules != null && feerules.size() > 0) {
						for (FeeRule feeRule : feerules) {
							FeeRuleCfgDesc feeRuleCfgDesc = feeRule.getFeeRuleCfg().getFeeRuleCfgDesc();
							if (feeRuleCfgDesc.getType() == FeeRuleType.meter) {
								Meter currentMeter = feeRule.getCurrentMeter();
								boolean result = false;
								if (currentMeter != null) {
									if (testRoomName == null || testRoomName.equals(room.getName())) {
										try {
											Meter newMeter = new Meter();
											ModelUtil.copy(currentMeter, newMeter, true);
											newMeter.setId(null);
											newMeter.setCheckTime(new Date());
											deleteMeterNew(currentMeter);
											List<Meter> meters = new ArrayList<>();
											meters.add(newMeter);
											addMetersNew(meters);
											result = true;
										} catch (Exception e) {
											logger.error(e.getMessage(),e);
										}
									}
								}
								if (result) {
									logger.info("=====修复房间：" + room.getName() + " 仪表："+feeRuleCfgDesc.getName() + "=====");
								}
							}
						}
					}
					logger.info("=====遍历房间：" + room.getName());
				}
			}
		}else{
			throw new ApplicationException("您无权限修复此类数据！");
		}
		return true;
	}
	
	//修复单个房间的抄表费用，删除费用接口会调用。
	public void repaireOneRoomMeterFee(Room room) {
		List<FeeRule> feerules = room.getFeeRules();
		if (feerules != null && feerules.size() > 0) {
			for (FeeRule feeRule : feerules) {
				FeeRuleCfgDesc feeRuleCfgDesc = feeRule.getFeeRuleCfg().getFeeRuleCfgDesc();
				if (feeRuleCfgDesc.getType() == FeeRuleType.meter) {
					Meter currentMeter = feeRule.getCurrentMeter();
					if (currentMeter != null) {
						try {
							Meter newMeter = new Meter();
							ModelUtil.copy(currentMeter, newMeter, true);
							newMeter.setId(null);
							newMeter.setCheckTime(new Date());
							deleteMeterNew(currentMeter);
							List<Meter> meters = new ArrayList<>();
							meters.add(newMeter);
							addMetersNew(meters);
						} catch (Exception e) {
							logger.error(e.getMessage(),e);
						}

					}
				}
			}
		}
	}
	
	
}
